哈啰中台业务 Flutter 实践
前言
2021年5月22日,哈啰技术沙龙-大前端的探索与实践,在杭州成功举办。
以下是由 @石旭盼 分享的主题《中台业务 Flutter 实践》
分享大纲
本次分享我们从移动端跨端的历史背景、哈啰出行在Flutter上的多方位实践以及我们对Flutter未来的展望这3大块,共6小点和大家一起分享一下我们平台移动端和业务中台在 Flutter 这个技术栈上的一些技术成果。
跨端技术的前世今生
Flutter 想必有些同学已经很熟悉了也在实际业务中接触过,它是 Google 近几年新出的一个全新 跨端技术框架,我们开发者可以使用 Dart 语言去构建 iOS 和 Android 应用。
为了让大家更好的了解 Flutter 技术栈,我们先来回顾一下移动端跨端技术的一些历史背景。
我们可以大致将跨端技术的历史分为3个时期:
Hybrid 时期
时间可以追溯到2009年前后,这个时期业界会陆陆续续使用 HTML、JS 等Web技术栈,再结合上移动端的WebView 容器来进行一些 APP的业务开发。
同时Webview容器通过对原生的一些能力的封装,提供给H5页面去使用来丰富 H5侧的能力以及打通H5和移动端的原生能力;
但是 浏览器内核的渲染独立于系统组件,比较难保证原生体验,渲染的效果和 性能也会差一些。
因此我们把这个时期称为Hybrid时期。
DSL 映射时期
我们再来到了2015年,这一年Facebook推出了React Native 这个框架,他与 Hybrid 最大的区别在于 View 渲染体系的不同,RN 抛弃了较低效的浏览器内核渲染模式,使用自定义的DSL映射对应的平台组件,然后渲染成原生平台的组件的方式来进行页面渲染。
但是这种渲染方式还需要 JS 和 原生之间频繁的通信,因此在有些场景会出现卡顿、白屏等一些性能问题,而且也会出现iOS和Android两端UI细节上的不一致性等问题。
因此我们把这个时期称为DSL映射时期。
自绘制引擎时期
接下来再来到2018年,Google在这一年推出Flutter,它通过Dart 语言来开发UI组件,所有的组件都基于自己的 Skia引擎进行渲染;基于这套自绘引擎Skia,Flutter不仅仅做到了消除平台之间的差异,而且在性能上也做到了与原生平台相媲美;
于此同时 Flutter 也拥有高性能的 与原生平台通讯的 Channel 机制 以及 完善的研发工具链。
因此我们把这个时期称为自绘制引擎时期。
好的,跨端技术的年代背景我们大致了解了;那我们再来对比一下这3个时期的跨端技术栈他们的优缺点。
各时期横向对比
我们分别从 开发语言、渲染方式、性能表现、研发效率、多端一致性、动态化以及社区生态的活跃度,这几个纬度 横向对比一下他们,很清晰的看出 Flutter 除了动态化的这个特性不足以外,其余特征都优于 RN 和 H5。
因此对于实际的项目而言 Flutter 的高效率、高性能、多端一致性以及性能表现上也已经具备大规模商用的标准。
这也是为什么Flutter 从推出以来热度一直高涨,而且目前在全球有大量的研发团队陆陆续续的在实际项目中去使用它。
上图就是今年 Google I/O 大会上的数据。目前在 Google Play 上,已经超过20万 个应用在使用 Flutter 了。Flutter 已然成为目前最流行的跨端技术框架了。
Flutter架构设计
接下来我们再来简单的回顾一下 Flutter 的架构设计。
Flutter 的架构主要分为三层,我们基于最上面的 Framework层提供的能力进行App 开发,并且运行在中间的 Engine 层,Engine 层也为我们提供了一些跨平台能力的支持和适配,当然我们也得益于 Engine 层的 Skia,Flutter 才可以自渲染UI组件,并且消除平台之间的差异,在渲染性能上也做到了与原生平台相媲美;
最下面一层就是嵌入层,就是把 Flutter 嵌入到原生平台中去,包括会去做 Suface的设置、线程设置以及插件等等。
多方位实践
哈啰出行 Flutter 体系化建设
在了解我们哈啰出行在Flutter上的一些实践之前,我们先来简单的了解一下哈啰出行的 Flutter 体系化建设是怎样的。
哈啰Flutter 业务使用情况
到目前为止我们已经有 3个APP,9条以上业务线 和 100多个页面 在使用 Flutter 技术栈了,于此同时在未来我们还会不断有业务线,尤其是新业务都会优先去考虑使用 Flutter;而且这些业务都是基于我们现有的哈啰Flutter体系完成业务研发的。
那么在这么多业务场景都在使用 Flutter 的时候,我们肯定会遇到很多技术问题和痛点。
本次分享我们总结了其中2个比较有意思和代表性的问题,和大家一起分享一下我们是如何利用技术手段去解决它们的。
首先,我们在平常的业务研发和需求迭代中,随着Flutter不断的在各个业务线中去应用,我们会遇到问题就是:
“如何能快速的将已有的原生的基础技术能力和中台业务能力赋予Flutter,快速的完善起Flutter 体系化的能力?”
其次,在现有功能完善的业务下,也不断会有新增的业务需求,那么我们也会遇到就是:
“我们怎么才能更好的利用 Flutter来提高现有业务原生侧的研发效率?”
我们把这2个问题都抛出来了,细心的同学可能已经发现了这2个问题其实就是原生和Flutter之间的相互依存,将原生能力赋予Flutter,提升Flutte的能力;将Flutter跨端能力赋予原生,来提升研发效率。
哈啰Flutter 架构概述
我们再来整体看一下我们哈啰出行Flutter架构概览,主要分为4层:
从下到上分别是 基础能力层,这一层最主要的是 我们 哈啰出行的原生能力,它包括 基础技术能力 和 业务中台能力;当然还有一些三方开发库的能力和Android、iOS 平台的能力。
再上面就是能力层,这里就是我们 哈啰 Flutter 最核心的能力了,它包括 Sparrow 微服务容器、Lumos跨端业务容器,还有HelloFlutterUI、HelloCache多端一致存储框架、HelloRouter多端一致路由库等等其他的技术能力。
再上面就是 我们的业务模块了,各业务均基于我们的能力层去研发业务;
最上面就是 产物层了,我们最终会把 Flutter构建成一个整体的二进制产物,再集成到我们的 App 中去。
在我们的能力层,有2个比较重要的容器:
一个是 Sparrow 微服务容器,我们会利用它来解决刚才说的问题1;
另一个是 Lumos 跨端业务容器,我们利用它来解决问题2;
微服务容器
上述章节中,我们也提及到在各个业务线不断的引入Flutter的时,我们急迫需要将原生平台上已有的中台业务能力和基础技术能力赋予Flutter,让我们快速搭建起 哈啰 Flutter 的体系化;同时也能搭建统一 哈啰 Flutter 开发行为,避免无效、重复的建设,也能加速业务变现,以及加快跨端技术栈的转型、降低技术研发成本、实现多端的一致性等。这也正是我们设计微服务容器的初衷。
我们叫这个微服务架构为 Sparrow,中文翻译是麻雀,有着麻雀虽小五脏俱全的寓意。但是这只麻雀如何能功能强大到五脏俱全呢,当然要羽翼丰满了,所以我们称每个独立微服务为羽毛。
那我们来看一下这只麻雀的架构是怎样的?
微服务架构设计
我们先简单的说一下Sparrow的架构原理:
Sparrow内部也是分层架构,其中最主要的部分就是中间的服务层,也是 微服务容器的核心能力层。
它从依次有 业务微服务、基础微服务以及三方微服务能力,而且各个微服务之间都相对独立;各个微服务内部会各自封装实现的细节和数据处理,并将对应的原生能力通过Sparrow的统一的API层提供给最上层的 Flutter 业务层去使用。
因此我们就能快速的将已有的原生业务中台能力和基础技术能力直接赋予整个哈啰Flutter体系了。
微服务容器原理
接下来我们看一下在实际业务开发中如何使用Sparrow微服务容器的。
首先,我们只需要将已经实现好的原生能力通过Sparrow的注解和定义好的唯一 Action 标识进行微服务的注册,接下来只要在 Flutter侧业务层 通过对应的 Action 就能获取到原生侧的对应能力了。
是不是很简洁而且方便使用;那我们这个微服务架构的内部机制是怎样的做的呢?
首先是服务注册:
其实现的核心是利用编译期注解,来收集和归类全部微服务注册到微服务容器中;
Android 侧使用 java的注解,iOS 侧也一样 只是利用 OC宏 去模拟类似注解的形式;在编译期我们会收集注册的全部微服务,统一到一个文件中;在应用启动后会读取这个文件,将全部的服务列表注册到微服务容器中,等待 Flutter 业务层去调用。
其次是调用流程:
这里我们用实际的一个业务例子来说明一下,我们的火车票业务为了提升用户的购票体验,当用户购票时我们需要直接填写用户当前位置最近的高铁站来方便用户购票;这个时候我们的火车票购票业务就需要原生的定位能力了。
所以,我们火车票 Flutter 业务层只需要通过微服务容器发起获取定位数据的需求,微服务容器会根据定位微服务的Action调用到Flutter侧的定位微服务,然后微服务通过容器将 Action 和 请求信息进行模型转换,再利用 Flutter Channel 通道,将数据传递到微服务容器的原生侧,原生侧会根据 Action 进行服务搜索 和 服务转换 或 服务的初始化,待找到原生服务后,将数据分发给定位的原生组件中,待原生组件获取到定位信息后,会将所需的数据 原路依次返回给 火车票 Flutter 业务层。
就这样我们完成了一次 Flutter业务 调用原生能力的需求。
至此我们借用微服务容器化的方式将已有的原生业务中台能力和基础技术能力,直接赋予Flutter侧,并快速的搭建起哈啰Flutter的体系了。
跨端业务容器
我们业务中台的消息平台、支付平台以及用户平台等等一些列业务;这些业务原生时期都已经具有完备的功能了,但是业务侧还会不断的有新的需求,如果还是基于之前原生开发模式去做的话,那我们需要分别在两端投入研发同学,但是呢可能会出现研发同学不够,偶尔也会出现两端不一致的情况,而且这种研发模式整体的研发效率也很一般。
所以我们需要一个能在业务逻辑开发上能减少研发同学的投入、而且保证两端一致性以及保留原生UI页面体验的一个 跨端业务容器。
这就是我们 跨端业务容器 的推出背景;我们称这个 跨端业务容器 为 Lumos。
Lumos 是《哈利波特》中的一个 照明咒,寓意更开阔明朗的未来,当然我们也借此 寓意着 通过我们的这个跨端业务容器 能给哈啰业务发展带来开阔明朗的未来。
跨端业务容器架构设计
上图是跨端业务容器Lumos的分层架构设计,我依次从上往下看,首先是
原生业务层:这一层主要保留了现有业务的原生页面,以及对体验有特定要求的一些业务页面。
容器协议层:主要是我们统一的 原生和Flutter 之间的 通讯协议 和 通信方式。
跨端业务层:主要是各个业务的自身的业务逻辑实现了,提供给原生层调用。
容器能力层:主要提供了 网络请求、定时器、数据解析和回传等一些基本能力,供跨端业务层去使用。
基础能力层:跨端业务容器是基于哈啰Flutter的整体技术能力,避免了重复建设。
所以 Lumos 的目的就是提供一个跨端的、一致性的、可复用的 Flutter 跨端业务容器;在保证研发提效、多端一致性的同时,也能兼顾 原生页面的流畅体验的需求。
跨端业务容器原理
接下来我们先看个实际例子,我们是如何使用 Lumos 这个跨端业务容器的?
图示显示的例子,首先要在Flutter侧的业务层 实现业务逻辑,并继承Lumos接口将其注册到跨端业务容器中,跨端业务容器会在Flutter引擎初始化后,将注册的业务能力统一提供到跨端业务容器的原生侧,等待我们原生侧使用。
当原生侧需要处理业务时,只需要通过 跨端业务容器 发起需求,跨端业务容器会通过内部机制 调起 Flutter 侧注册的业务,待逻辑处理完成后,再原路将数据返回给 业务原生层 供业务进行下一步的操作。
也是很简单和方便的使用,那这个跨端业务容器的内部机制是怎样的呢?
我们继续拿实际的业务场景来说明下,就拿我们最熟悉的账号模块的用户登录功能来作为例子吧;在我们某一次新需求开发时就将新的登录需求功能利用跨端业务容器做到了Flutter层,并提供给原生的UI页面使用。
基于上述我们跨端业务容器整体的流程大致是,当账户模块的原生UI层 发起 用户登录需求时,将登录功能URI和业务参数提供给跨端业务容器,跨端业务容器将信息封装和处理后,再经 Flutter Channel 传到 跨端业务容器 Lumos 的 Flutter 侧,Flutter 侧通过功能URI进行检索,待命中到对应的账号模块的登录能力后,再将数据等一列信息分发到账号模块 Flutter层进行业务处理,待处理完成后,会将结果数据进行信息转换后,通过Flutter Channel 返回给原生UI层,原生UI层 再根据实际的结果进行 UI页面的操作。
就此我们完成了一次完整的原生UI结合跨端业务容器处理了一个实际业务需求的流程。
当然,跨端业务容器 Lumos的使用场景不只局限于业务逻辑的开发提效。业务所处领域的数据,流程,规则等是可以通过Lumos统一集中在一起,通过状态集中管理来更新,监听,并维护我们的应用。
小结
经过对上述2个问题的解决以及解决方案的架构设计;我们不难发现 原生侧 和 Flutter 之间其实就是一个相辅相成的关系,也没有谁一定要代替谁这么一说。
还是围绕着将原生能力赋予跨端平台,来提升跨端平台体系化的能力;再通过跨端能力赋予原生,来提升原生侧研发效率。
这也是我们近几年甚至未来长期的移动端研发模式。
展望未来
我们使用容器化技术手段,优化了业务需求交付的模式、快速搭建起哈啰Flutter体系,同时也加速了新业务的变现、提升了业务研发效率、解决多端一致性等问题。
未来我们还会在跨端之间多媒体资源内存共享、Flutter稳定性监控和建设、Flutter动态化实践以及Flutter SDK版本平滑升级等方面继续探索和验证。
The End
如果你觉得这篇内容对你挺有启发,请你轻轻点下小手指,帮我两个小忙呗:
1、点亮「在看」,让更多的人看到这篇满满干货的内容;
2、关注公众号「哈啰技术」,可第一时间收到最新技术推文。
如果喜欢就点个👍喔,有您的喜欢⛽️,我们会更有动力输出有价值的技术分享滴;